package de.velvettear.bruteforce.kernel;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;

public class BruteForce { 
	
	public static String next(char[] charset, String word) {
		if (word == null) {
			word = "";
		}
		return next(charset, word, word.length() - 1);
	}
	
	public static String next(char[] charset, String word, int position) {		
		if (word == null) {
			word = "";
		}
		
		char[] words = word.toCharArray();
		
		if (words.length == 0) {
			return String.valueOf(charset[0]);
		} else if (words[position] == charset[charset.length - 1]) {
			words[position] = charset[0];
			if (position > 0) {
				return next(charset, String.valueOf(words), position - 1);
			} else {
				return charset[0] + String.valueOf(words);
			}
		} else {
			for (int i = 0; i < charset.length; i++) {
				if (words[position] == charset[i]) {
					words[position] = charset[i+1];
					break;
				}
			}
			
			return String.valueOf(words);
		}		
	}
	
	public static BigInteger calculatePossibilities(int maxLength, int chars) {		
		return calculatePossibilities(maxLength, chars, null);
	}
	
	public static BigInteger calculatePossibilities(int maxLength, int chars, BigInteger lastIndex) {		
		BigInteger possibilities = new BigInteger(String.valueOf(0));
		BigInteger characters = new BigInteger(String.valueOf(chars));
		
		possibilities = characters.pow(maxLength);
		
		for (int i = 1; i < maxLength; i++) {
			possibilities = possibilities.add(characters.pow(i));
		}
			
		if (lastIndex != null) {
			possibilities = possibilities.subtract(lastIndex);
		}
				
		return possibilities;
	}
	
	public static int calculatePercentageDone(BigInteger done, BigInteger total) {		
		BigDecimal percentage = (new BigDecimal(done).divide(new BigDecimal(total), 4, RoundingMode.HALF_UP)).multiply(new BigDecimal(String.valueOf(100)));
		
		return percentage.intValue();
	}
	
	public static BigDecimal calculateAveragePerMillisecond(long start, BigInteger wordsCreated) {
		BigDecimal timeSpent = new BigDecimal((System.currentTimeMillis() - start));
		
		BigDecimal average = new BigDecimal(wordsCreated).divide(timeSpent, 2, RoundingMode.HALF_UP);
		
		return average;
	}
	
	public static BigDecimal calculateAveragePerSecond(long start, BigInteger wordsCreated) {
		BigDecimal timeSpent = new BigDecimal((System.currentTimeMillis() - start) / 1000);
		
		BigDecimal average = new BigDecimal(wordsCreated).divide(timeSpent, 2, RoundingMode.HALF_UP);
		
		return average;
	}
	
	public static BigDecimal calculcateRemainingTime(BigDecimal average, BigInteger wordsCreated, BigInteger possibilities) {
		BigDecimal remaining = new BigDecimal(possibilities).subtract(new BigDecimal(wordsCreated));
		
		BigDecimal zero = new BigDecimal(String.valueOf(0));
		
		if (average.compareTo(zero) == 0) {
			return zero;
		}
		
		remaining = remaining.divide(average, 2, RoundingMode.HALF_UP);
		
		return remaining;
	}
		
}
